//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include "CDisplay.h"

#define DISPLAYDEBUG    DEBUGLEVEL

Int32 g_screenWidth = 240;
Int32 g_screenHeight = 220;

CDisplay* g_displayDriver;

EXTERN_C IDeviceDriver * GetDisplayDriver()
{
    assert(g_displayDriver);

    return g_displayDriver;
}

EXTERN_C ECode DisplayDriver_Initialize()
{
    CDisplay* displayDriver = new CDisplay;
    if (!displayDriver) {
        GFX_ERROR_MESSAGE("Not enough memory\n");

        return E_OUT_OF_MEMORY;
    }

    ECode ec = displayDriver->constructor();
    if (GFX_FAILED(ec)) {
        delete displayDriver;

        return ec;
    }

    displayDriver->AddRef();
    g_displayDriver = displayDriver;

    return NOERROR;
}

EXTERN_C ECode DisplayDriver_Destory()
{
    if (g_displayDriver) {
        delete g_displayDriver;
        g_displayDriver = NULL;
    }

    return NOERROR;
}

EXTERN_C ECode SetScreenSize(
        /* [in] */ Int32 width,
        /* [in] */ Int32 height)
{
    kprintf(">>>>>>>>>>>> SetScreenSize >>>>>>>>>>\n");

    return NOERROR;
}

EXTERN_C ECode AddDisplayLoadCallback(
        /* [in] */ displayFunc load)
{
    assert(load);
    g_displayDriver->m_renderFunc = load;

    return NOERROR;
}

CDisplay::~CDisplay()
{
    if (m_frameBuffer) {
        free((Void *)m_frameBuffer);
        m_frameBuffer = NULL;
    }
}

ECode CDisplay::constructor()
{
    assert(0 != g_screenWidth && 0 != g_screenHeight);
//    assert(m_renderFunc);

    GFX_EXPRESSION(DISPLAYDEBUG,
        kprintf("Screen width = %d, height = %d\n",
        g_screenWidth, g_screenHeight));

    m_frameBuffer = (Address)malloc(g_screenWidth * g_screenHeight * 4);
    if (!m_frameBuffer) {
        GFX_ERROR_MESSAGE("Not enough memory\n");

        return E_OUT_OF_MEMORY;
    }

    return NOERROR;
}

ECode CDisplay::Control(
    /* [in] */ Int32 controlCode,
    /* [in] */ const MemoryBuf &ebbInData,
    /* [out] */ MemoryBuf* outData,
    /* [out] */ IEvent** completionEvent)
{
    ECode ec = NOERROR;

    switch (controlCode) {
        // Init the display hardware
        //
        case 3: {
            Address* addr =  (Address *)outData->GetPayload();
            *addr = (Address)m_frameBuffer;
            outData->SetUsed(sizeof(UInt32));

            break;
        }

        // Get baseplane format
        //
        case 7: {
            FrameBufferFormat format;

            if (!outData) {
                GFX_ERROR_MESSAGE("Invalid argument\n");
                return E_INVALID_ARGUMENT;
            }

            assert(outData->GetPayload());

            format.Color = COLOR_ARGB;
            format.Bpp = 32;
            format.Width = g_screenWidth;
            format.Height = g_screenHeight;

            outData->Copy((Byte *)&format, sizeof(FrameBufferFormat));

            break;
        }

        // Render
        //
        case 11: {
            RenderFrame updateFrame;

            if (ebbInData.IsEmpty()) {
                updateFrame.srcBuffer.addr = m_frameBuffer;
                updateFrame.srcBuffer.width = g_screenWidth;
                updateFrame.srcBuffer.height = g_screenHeight;
                updateFrame.srcBuffer.pitch = g_screenWidth * 4;
                updateFrame.srcBuffer.pixelFormat = PixelFormat_ARGB;
                updateFrame.srcBuffer.bpp = 32;
                updateFrame.startX = 0;
                updateFrame.startY = 0;
            }
            else {
                memcpy((Void *)&updateFrame,
                    (Void *)ebbInData.GetPayload(),
                    sizeof(RenderFrame));
            }

            GFX_EXPRESSION(DISPLAYDEBUG,
                kprintf("CDisplay parameter: addr = 0x%08x "
                        "src(%d, %d, %d, %d, %d), "
                        "dst(%d, %d), m_orientation = %d\n",
                    updateFrame.srcBuffer.addr,
                    updateFrame.startX, updateFrame.startY,
                    updateFrame.srcBuffer.width, updateFrame.srcBuffer.height,
                    updateFrame.srcBuffer.pitch,
                    updateFrame.startX, updateFrame.startY,
                    0));

            ec = m_renderFunc(
                updateFrame.srcBuffer.addr,
                updateFrame.startX, updateFrame.startY,
                updateFrame.srcBuffer.width, updateFrame.srcBuffer.height,
                updateFrame.srcBuffer.pitch,
                updateFrame.startX, updateFrame.startY,
                0);

            break;
        }

        default:
            ec = E_NOT_IMPLEMENTED;
            break;
    }

    return ec;
}
